#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>

#include "error.h"
#include "main.h"
#include "util.h"
#include "configuration.h"

#define CONFIGURATION_ERROR_LENGTH 512
char configuration_error[CONFIGURATION_ERROR_LENGTH] = {0};

dictionary* config_dictionary = NULL;

int configuration_error_callback(const char* format, ...) {
    int ret;
    va_list argptr;
    va_start(argptr, format);
    ret = vsnprintf(configuration_error, CONFIGURATION_ERROR_LENGTH, format, argptr);
    va_end(argptr);
    return ret;
}

// TODO add a field to return error message instead calling error().
int read_configuration(void) {
    if (config_dictionary != NULL) {
        // Don't read again.
        return 0;
    }

    dictionary* dict = NULL;
    iniparser_set_error_callback(configuration_error_callback);

    do {
        if (GLOBAL_ARGS.config_file != NULL) {
            dict = iniparser_load(GLOBAL_ARGS.config_file);
            if (dict == NULL) {
                error(0, 0, "Unable to open configuration file %s", configuration_error); 
                return -1;
            } else {
                break;
            }
        }
        
        dict = iniparser_load("/etc/" PROGRAM_NAME "/config.conf");
        if (dict != NULL) {
            break;
        }
        
        char* home_dir = getenv("HOME");
        if (home_dir != NULL) {
            size_t home_len = strlen(home_dir);
            const char suffix[] = "/.config/" PROGRAM_NAME "/config.conf";
            char* home_path = (char*) malloc(home_len + sizeof(suffix));
            memcpy(home_path, home_dir, home_len);
            memcpy(home_path + home_len, suffix, sizeof(suffix));
            
            dict = iniparser_load(home_path);
            if (dict != NULL) {
                break;
            }
        }
    } while(0);
    
    config_dictionary = dict;
    return config_dictionary == NULL ? 0 : 1;
}

int parse_configuation(void) {
    const char* field;
    assert(config_dictionary != NULL);
    
    field = iniparser_getstring(config_dictionary, "global:host", NULL);
    if (field != NULL) {
        GLOBAL_ARGS.portal_host = string_duplicate(field);
    }
    
    field = iniparser_getstring(config_dictionary, "global:search", NULL);
    if (field != NULL) {
        GLOBAL_ARGS.portal_search = string_duplicate(field);
    }
    
    field = iniparser_getstring(config_dictionary, "global:bind", NULL);
    if (field != NULL) {
        GLOBAL_ARGS.bind_interface = string_duplicate(field);
    }
    
    field = dictionary_get(config_dictionary, "auth:username", NULL);
    if (field != NULL) {
        GLOBAL_ARGS.auth_username = string_duplicate(field);
    }
    
    field = dictionary_get(config_dictionary, "auth:password", NULL);
    if (field != NULL) {
        GLOBAL_ARGS.auth_password = string_duplicate(field);
    }
    return 0;
}

void free_configuation(void) {
    if (config_dictionary == NULL) {
        return;
    }
    iniparser_freedict(config_dictionary);
}
